const { cache } = require('../config/defaultConfig');

const refreshRes = (stats, res) => {
  const { maxAge, expires, cacheControl, lastModified, etag } = cache;
  if (expires) {
    res.setHeader('Expires', (new Date(Date.now()+maxAge*1000)).toUTCString());
  }
  if (cacheControl) {
    res.setHeader('Cache-Control', `public, max-age=${maxAge}`);
  }
  if (lastModified) {
    res.setHeader('Last-Modified', stats.mtime.toUTCString());
  }
  if (etag) {
    res.setHeader('ETag', `${stats.size} - ${stats.mtime}`);
  }
};

module.exports = (stats, req, res) => {
  refreshRes(stats, res);
  const lastModified = req.headers['if-modified-since'];
  const etag = req.headers['if-none-match'];
  if (!lastModified && !etag) {
    return false;
  }
  if (lastModified && lastModified !== res.getHeader('Last-Modified')) {
    return false;
  }
  if (etag && etag !== res.getHeader('ETag')) {
    return false;
  }
  return true;
};

/**
 * 缓存
 * 强制缓存
 * - 概念: 客户端访问服务器请求资源,请求成功之后客户端会缓存到本地,缓存到本地之后,如果以后客户端再请求该资源此时不需要请求服务器了,直接访问本地的就可以。
 * - 实现: 1.浏览器会将文件缓存到Cache目录,第二次请求时浏览器会先检查Cache目录下是否含有该文件,如果有，并且还没到Expires设置的时间,即文件还没有过期,
 *          那么此时浏览器将直接从Cache目录中读取文件,而不再发送请求;
 *        2.Expires是服务器响应消息头字段,在响应http请求时告诉浏览器在过期时间前浏览器可以直接从浏览器缓存取数据,而无需再次请求,
 *          这是HTTP1.0的内容,现在浏览器均默认使用HTTP1.1,所以基本可以忽略;
 *        3.Cache-Control与Expires的作用一致，都是指明当前资源的有效期，控制浏览器是否直接从浏览器缓存取数据还是重新发请求到服务器取数据,
 *          如果同时设置的话,其优先级高于Expires
 * - 说明: 把资源缓存在客户端，如果客户端再次需要此资源的时候，先获取到缓存中的数据，看是否过期，如果过期了。再请求服务器
 *         如果没过期，则根本不需要向服务器确认，直接使用本地缓存即可。
 *         Cache-Control private客户端可以缓存, public客户端和代理服务器都可以缓存
 *         max-age=60 缓存内容将在60秒后失效
 *         no-cache 需要使用对比缓存验证数据,强制向源服务器再次验证.
 *         禁用强制缓存 no-store 所有内容都不会缓存，强制缓存和对比缓存都不会触发。
 *         兼用强制缓存和对比缓存
 * - 使用: 把资源缓存在客户端，如果客户端再次需要此资源的时候，先获取到缓存中的数据，看是否过期，如果过期了。再请求服务器
 *         如果没过期，则根本不需要向服务器确认，直接使用本地缓存即可
 *         res.setHeader('Expires', new Date(Date.now() + 30 * 1000).toUTCString());
 *         res.setHeader('Cache-Control', 'max-age=30');
 * 对比缓存
 * - 概念: 浏览器第一次请求数据时,服务器会将缓存标识与数据一起返回给客户端,客户端将二者备份至缓存数据库中。
 *         再次请求数据时,客户端将备份的缓存标识发送给服务器,服务器根据缓存标识进行判断,判断成功后,返回304状态码,通知客户端比较成功,可以使用缓存数据。
 * - 使用: Last-Modified
 *        1.Last-Modified: 响应时告诉客户端此资源的最后修改时间
 *        2.If-Modified-Since: 当资源过期时(使用Cache-Control标识的max-age),发现资源具有Last-Modified声明,则再次向服务器请求时带上头If-Modified-Since
 *        3.服务器收到请求后发现有头If-Modified-Since则与被请求资源的最后修改时间进行比对。若最后修改时间较新,说明资源又被改动过,则响应最新的资源内容并返回200状态码
 *        4.若最后修改时间和If-Modified-Since一样,说明资源没有修改,则响应304表示未更新,告知浏览器继续使用所保存的缓存文件。
 *        res.setHeader('Last-Modified', stat.ctime.toGMTString());
 *        Etag
 *        ETag是实体标签的缩写,根据实体内容生成的一段hash字符串,可以标识资源的状态。当资源发生改变时,ETag也随之发生变化。ETag是Web服务端产生的,然后发给浏览器客户端。
 *        1.客户端想判断缓存是否可用可以先获取缓存中文档的ETag,然后通过If-None-Match发送请求给Web服务器询问此缓存是否可用。
 *        2.服务器收到请求,将服务器的中此文件的ETag,跟请求头中的If-None-Match相比较,
 *          如果值是一样的,说明缓存还是最新的,Web服务器将发送304 Not Modified响应码给客户端表示缓存未修改过,可以使用。
 *        3.如果不一样则Web服务器将发送该文档的最新版本给浏览器客户端
 *        let etag = md5.update(content).digest('hex');
 *        let etag = crypto.createHash('md5').update(content).digest('hex');
 *        let etag = `${stat.ctime}-${stat.size}`;
 *        res.setHeader('Etag', etag);
 */
